#pragma once
#include <queue>
#include <iostream>
#include <unistd.h>
#include <algorithm>
#define NUM 10


template<class T>
class ThreadPool
{
    private:
    void Lock()
    {
        pthread_mutex_lock(&mutex_);
    }
    void UnLock()
    {
        pthread_mutex_unlock(&mutex_);
    }
    void Wait()
    {
        pthread_cond_wait(&cond_,&mutex_);
    }
    void WakeUp()
    {   
        pthread_cond_signal(&cond_);
    }
    bool Is_Empty()
    {
        return task_queue_.size() == 0;
    }
    public:
    ThreadPool(int num=NUM)
    :thread_num_(num)
    {}
    ~ThreadPool()
    {
        pthread_cond_destroy(&cond_);
        pthread_mutex_destroy(&mutex_);
    }
    static void* Routinue(void* arg)
    {
        pthread_detach(pthread_self());
        ThreadPool* tmp=(ThreadPool*)arg;
        while(1)
        {
            tmp->Lock();
            while(tmp->Is_Empty())
            {
                tmp->Wait();
            }
            T task;
            tmp->Pop(task);
            tmp->UnLock();

            task.Run();
        }
    }
    void Pop(T& task)
    {
        task=task_queue_.front();
        task_queue_.pop();
    }
    void Push(const T& task)
    {
        Lock();
        task_queue_.push(task); 
        UnLock();
        WakeUp();
    }
    void Init_Thread_Pool()
    {
        pthread_t tid;
        for(int i=0;i<thread_num_;i++)
        {
            pthread_create(&tid,nullptr,Routinue,this);
        }
    }

    private:
    std::queue<T> task_queue_;
    int thread_num_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;
};